package nyist.media.aspect;

import com.hazelcast.util.collection.ArrayUtils;
import lombok.extern.slf4j.Slf4j;
import nyist.media.annotation.Log;
import nyist.media.repository.LogRepository;
import nyist.media.service.AdminService;
import nyist.media.utils.NetworkUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;


/**
 * @author : dcf
 * @date : 2019/3/11
 */

@Aspect
@Component
@Slf4j
public class LogAspect {

    @Autowired
    private LogRepository logRepository;
    @Autowired
    private AdminService adminService;

    /**
     * 默认忽略参数
     */
    private static final String[] DEFAULT_IGNORE_PARAMETERS = {
            "password",
            "pwd",
            "rePassword",
            "currentPassword"};

    /**
     * 整个表达式可以分为五个部分： 1、execution(): 表达式主体。 2、第一个*号：表示返回类型，*号表示所有的类型。
     * 3、包名：表示需要拦截的包名，后面的两个句点表示当前包和当前包的所有子包，com.sample.service.impl包、子孙包下所有类的方法。
     * 4、第二个*号：表示类名，*号表示所有的类。
     * 5、*(..):最后这个星号表示方法名，*号表示所有的方法，后面括弧里面表示方法的参数，两个句点表示任何参数。
     */
    @Pointcut("@annotation(nyist.media.annotation.Log)")
    public void controllerAspect() {
    }

    /**
     * 后置通知
     *
     * @param joinpoint 切入点
     */
    @After("controllerAspect()")
    public void after(JoinPoint joinpoint) {
        saveLog(joinpoint);
    }

    /**
     * 生成操作日志
     */
    private void saveLog(JoinPoint point) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        Date now = new Date();
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Method method = methodSignature.getMethod();

        StringBuilder sb = new StringBuilder();
        sb.append("uri=").append(request.getRequestURI()).append(System.lineSeparator());
        if (HttpMethod.PUT.matches(request.getMethod())) {
            // PUT请求获取不到参数 SpringMVC默认不支持  data:{_method:"PUT", id:issueId,userId:userId},
        } else {
            Map<String, String[]> parameterMap = request.getParameterMap();
            for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
                String paramName = entry.getKey();
                if (!ArrayUtils.contains(DEFAULT_IGNORE_PARAMETERS, paramName)) {
                    sb.append("params=").append(paramName).append("=").append(parameterMap.get(paramName)).append(",");
                }
            }
        }
        nyist.media.entity.admin.Log log = new nyist.media.entity.admin.Log();
        log.setCreateDate(now);
        log.setModifyDate(now);
        log.setIp(NetworkUtil.getIpAddress(request));
        log.setOperator(adminService.getCurrent().getName());
        log.setOperation(method.getAnnotation(Log.class).value());
        log.setParams(new String(sb));
        logRepository.save(log);
    }
}

